//
// Created by pzw on 24-1-4.
//

#include "CxxHandler.h"
#include <pthread.h>

#define LOOP 99999999

static pthread_key_t thread_looper_key;
static CxxLooper *threadLooper = nullptr;
static pthread_once_t looper_alloc_key_once = PTHREAD_ONCE_INIT;

CxxLooper::CxxLooper() = default;

CxxLooper::~CxxLooper() = default;

/**
 * 这个函数会绑定到pthread_key_create创建的线程, 线程消失后自动调用, 析构
 *
 * @param arg 参数
 */
static void destroy_pthread_key(void *arg) {
    delete threadLooper;
}

/**
 * 这个函数会:
 * 1. pthread_key_create 创建线程 pthread
 * 2. 创建 Looper
 * 3. pthread_setspecific 绑定 pthread 和 Looper
 */
static void alloc_pthread_key() {
    pthread_key_create(&thread_looper_key, destroy_pthread_key);
    threadLooper = new CxxLooper();
    pthread_setspecific(thread_looper_key, threadLooper);
}

/**
 * 准备looper, 这里会把looper和Thread绑定, pthread_getspecific类似View.setTag
 *
 * @return Looper *
 */
CxxLooper *CxxLooper::prepare() {
    // 传入 地址&looper_alloc_key_once, 函数alloc_pthread_key
    pthread_once(&looper_alloc_key_once, alloc_pthread_key);
    return (CxxLooper *) pthread_getspecific(thread_looper_key);
}

/**
 * 获取绑定的Looper *, pthread_getspecific类似View.getTag
 *
 * @return Looper *
 */
CxxLooper *CxxLooper::getThreadLocalLooper() {
    return (CxxLooper *) pthread_getspecific(thread_looper_key);
}

/**
 * loop()
 *
 * 1. 如果你需要把这个函数运行到你的进程的主线程中，那么这个函数，
 *    就是你的主线程，所有主线程操作都应该在这个函数中进行，否则，你将会被这个线程阻塞；
 * 2. 你可以使用两个线程，其中一个线程专门进行队列消费，你就可以使用这个loop进行操作，
 *    在其他线程通过handler发送消息到该线程中；
 */
void CxxLooper::loop() {
    CxxLooper *cxxLooper = getThreadLocalLooper();
    for (int i = 0; i < LOOP; i++) {
        printf("CxxLooper_loop >>> dequeue msg.\n");
        CxxMessage *msg = cxxLooper->deQueue(); /* might block */
        if (msg->callBack != nullptr) {
            msg->callBack(msg);
        } else {
            if (msg->handler != nullptr) {
                msg->handler->handleMessage(msg);
            }
        }
        CxxMessage::recycle(msg);
    }
}

/**
 * 入队
 *
 * @param msg 消息
 */
void CxxLooper::enQueue(CxxMessage *msg) {
    if (!msg) {
        return;
    }

    mMsgQ.enQueue(msg);
}

/**
 * 出队
 *
 * @return Message *
 */
CxxMessage *CxxLooper::deQueue() {
    return mMsgQ.deQueue();
}

